/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus' Graphical User Interface
// Copyright (C) 2012-2025 Bruno Van de Velde (vdv_b@tgui.eu)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
//    you must not claim that you wrote the original software.
//    If you use this software in a product, an acknowledgment
//    in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
//    and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <TGUI/Font.hpp>
#include <TGUI/Backend/Window/Backend.hpp>
#include <TGUI/Backend/Font/BackendFont.hpp>
#include <TGUI/Loading/Deserializer.hpp>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace tgui
{
    namespace
    {
        Font globalFont;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    void Font::setGlobalFont(const Font& font)
    {
        globalFont = font;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    Font Font::getGlobalFont()
    {
        if (!globalFont && isBackendSet())
            globalFont = getBackend()->createDefaultFont();

        return globalFont;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    Font::Font(std::nullptr_t) noexcept
    {
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    Font::Font(const String& id) :
        Font{Deserializer::deserialize(ObjectConverter::Type::Font, id).getFont()}
    {
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    Font::Font(const char* id) :
        Font(String{id})
    {
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    Font::Font(const void* data, std::size_t sizeInBytes) :
        m_backendFont{getBackend()->createFont()}
    {
        m_backendFont->loadFromMemory(data, sizeInBytes);
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    Font::Font(std::shared_ptr<BackendFont> backendFont, String id) :
        m_backendFont(std::move(backendFont)),
        m_id(std::move(id))
    {
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    const String& Font::getId() const
    {
        return m_id;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    Font::operator bool() const
    {
        return m_backendFont != nullptr;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    bool Font::operator==(std::nullptr_t) const
    {
        return m_backendFont == nullptr;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    bool Font::operator!=(std::nullptr_t) const
    {
        return m_backendFont != nullptr;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    bool Font::operator==(const Font& right) const
    {
        return m_backendFont == right.m_backendFont;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    bool Font::operator!=(const Font& right) const
    {
        return m_backendFont != right.m_backendFont;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    FontGlyph Font::getGlyph(char32_t codePoint, unsigned int characterSize, bool bold, float outlineThickness) const
    {
        if (m_backendFont != nullptr)
            return m_backendFont->getGlyph(codePoint, characterSize, bold, outlineThickness);
        else
        {
            TGUI_PRINT_WARNING("Font::getGlyph called on font that wasn't initialized");
            return {};
        }
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    float Font::getKerning(char32_t first, char32_t second, unsigned int characterSize, bool bold) const
    {
        if (m_backendFont)
            return m_backendFont->getKerning(first, second, characterSize, bold);
        else
            return 0;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    float Font::getLineSpacing(unsigned int characterSize) const
    {
        if (m_backendFont)
            return m_backendFont->getLineSpacing(characterSize);
        else
            return 0;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    float Font::getFontHeight(unsigned int characterSize) const
    {
        if (m_backendFont)
            return m_backendFont->getFontHeight(characterSize);
        else
            return 0;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    void Font::setSmooth(bool smooth)
    {
        if (m_backendFont)
            m_backendFont->setSmooth(smooth);
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    bool Font::isSmooth() const
    {
        if (m_backendFont)
            return m_backendFont->isSmooth();
        else
            return true;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    std::shared_ptr<BackendFont> Font::getBackendFont() const
    {
        return m_backendFont;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
